package com.clw.runtime;

import java.util.Stack;

/**
 * Created by chengliwei on 2019/1/10.
 */
public class VMStack { // 线程私有，保存方法执行的状态

    private Stack<Frame> stack;

    public VMStack() {
        stack = new Stack<>();
    }

    public void push(Frame frame) {
        stack.push(frame);
    }

    public Frame current() {
        return stack.peek();
    }

    public Frame pop() {
        return stack.pop();
    }

    public static class Frame {
        // 随着方法调用而创建，随着方法结束而销毁
        // 栈帧本地私有，不可能引用其他线程的栈帧

        public Frame(int maxLocals, int maxStack) {
            this.localVariable = new LocalVariable(maxLocals);
            this.operandStack = new OperandStack(maxStack);
        }

        public LocalVariable localVariable; // 局部变量表
        public OperandStack operandStack;
        public int constantPoolIndex; // 指向当前方法所属的类的运行时常量池的【引用】
    }

    // 本地变量表和操作数栈 容量编译期确定，并通过相关方法的Code属性保存及提供给栈帧使用
    public static class LocalVariable {

        // JVM使用局部变量表来完成方法调用时的参数传递
        // 调用类方法时，从0开始
        // 调用实例方法时，第0个一定是this
        // 大小已经由编译器确定
        private int maxLocals;
        private int[] variables;
        private int current;

        public LocalVariable(int maxLocals) {
            this.maxLocals = maxLocals;
            this.variables = new int[maxLocals];
        }

        public void setInt(int v) {
            variables[current++] = v;
        }

        public int getInt(int i) {
            return variables[i];
        }

        public void setFloat(float v) {
            variables[current++] = Float.floatToIntBits(v);
        }

        public float getFloat(int i) {
            int byteValue = variables[i];
            return Float.intBitsToFloat(byteValue);
        }

        public void setLong(long v) {
            variables[current++] = (int) v;
            variables[current++] = (int) (v >> 32);
        }

        public long getLong(int i) {
            int low = variables[i];
            int high = variables[++i];
            return (long) high << 32 | low;
        }

        public void setDouble(double v) {
            long lv = Double.doubleToLongBits(v);
            setLong(lv);
        }

        public double getDouble(int i) {
            long lv = getLong(i);
            return Double.longBitsToDouble(lv);
        }

    }

    public static class OperandStack {

        // 后进先出栈 LIFO
        // 大小已经由编译器确定
        private int maxStacks;
        private int current;
        private int[] stack;

        public OperandStack(int maxStacks) {
            this.maxStacks = maxStacks;
            stack = new int[maxStacks];
        }

        public void pushInt(int v) {
            stack[current] = v;
            current++;
        }

        public int popInt() {
            current--;
            return stack[current];
        }
    }

}
